﻿using Athena.Http;
using BuddHa.Common.JsonOpex;
using BuddHa.IRS.Options;
using BuddHa.IRS.ResponseModel;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace BuddHa.IRS
{
    public class IrsWebProtcol
    {
        public const string ClientName = "irs_http1_1";
        public const string SuccessCode = "00";
        public const string RequestKeyExpire = "11";
        public const string CityRequestKeyExpire = "07";
        protected ILogger Logger { get; }
        protected IJsonOpexSerializer _jsonOpexSerializer { get; }
        protected IHttpRequester HttpRequester { get; }
        protected CameraOptions _cameraOptions { get; set; }
        protected ConcurrentDictionary<string, string> _requestSecretDictionary = new ConcurrentDictionary<string, string>();
        protected ConcurrentDictionary<string, string> _appSecretDictionary = new ConcurrentDictionary<string, string>();

        public IrsWebProtcol(IHttpRequester httpRequester, ILogger<IrsWebProtcol> logger, IJsonOpexSerializer jsonOpexSerializer, IOptions<CameraOptions> options)
        {
            HttpRequester = httpRequester;
            Logger = logger;
            _jsonOpexSerializer = jsonOpexSerializer;
            _cameraOptions = options.Value;
            foreach (var option in _cameraOptions.IrsConfig)
            {
                if (!_appSecretDictionary.ContainsKey(option.AppKey))
                {
                    _appSecretDictionary.TryAdd(option.AppKey, option.AppSecret);
                }
            }
        }

        public async Task<string> GetRequestSecret(string appKey, bool checkDic, string url)
        {
            if (string.IsNullOrWhiteSpace(appKey))
            {
                throw new Exception("获取requestSecret失败,appKey不可为空!");
            }
            else
            {
                if (checkDic)
                {
                    if (_requestSecretDictionary.ContainsKey(appKey))
                    {
                        return _requestSecretDictionary[appKey];
                    }
                }
            }

            if (!_appSecretDictionary.ContainsKey(appKey))
            {
                foreach (var option in _cameraOptions.IrsConfig)
                {
                    _appSecretDictionary.TryAdd(option.AppKey, option.AppSecret);
                }
            }
            var requestTime = TimeProcess.GetTimeStamp();
            var reSignStr = $"{appKey}{_appSecretDictionary[appKey]}{requestTime}";
            var signStr = Md5Utils.GetStrMd5_32X(reSignStr);
            string requestUri = string.Format(url, appKey, requestTime, signStr);
            var response = await GetRequest<BaseIrsResponse<GetRequestSecretResponse>>(requestUri, ClientName);
            if (response == null)
            {
                throw new Exception("获取requestSecret失败,请求结果为空!");
            }
            if (response.Code != SuccessCode)
            {
                throw new Exception($"获取requestSecret失败，code: {response.Code}, msg: {response.Msg}");
            }
            if (response.Datas == null)
            {
                throw new Exception($"获取requestSecret失败，返回datas为空");
            }
            if (_requestSecretDictionary.ContainsKey(appKey))
            {
                _requestSecretDictionary[appKey] = response.Datas.RequestSecret;
            }
            else
            {
                _requestSecretDictionary.TryAdd(appKey, response.Datas.RequestSecret);
            }
            return _requestSecretDictionary[appKey];
        }

        public async Task<List<TyphoonRouteResponse>> GetTyphoonRoute(string appKey, string bianhao, string requestKeyUri, string billUri, bool reCount = false)
        {
            var requestSecret = await GetRequestSecret(appKey, true, requestKeyUri);
            var requestTime = TimeProcess.GetTimeStamp();
            var reSignStr = $"{appKey}{requestSecret}{requestTime}";
            var signStr = Md5Utils.GetStrMd5_32X(reSignStr);
            string requestUri = string.Format(billUri, requestTime, signStr, appKey, bianhao);
            var response = await GetRequest<BaseIrsResponse<List<TyphoonRouteResponse>>>(requestUri, ClientName);
            if (response == null)
            {
                throw new Exception("获取台风路径信息失败,返回结果为空!");
            }
            if (response.Code != SuccessCode)
            {
                if (response.Code == RequestKeyExpire && !reCount)
                {
                    await GetRequestSecret(appKey, false, requestKeyUri);
                    return await GetTyphoonRoute(appKey, bianhao, requestKeyUri, billUri, true);
                }
                throw new Exception($"获取台风路径信息失败，code: {response.Code}, msg: {response.Msg}");
            }
            return response.Datas;
        }

        public async Task<string> GetCollaboraiveWork(string appKey, string typhoonId, int status, string requestKeyUri, string billUri, bool reCount = false)
        {
            var requestSecret = await GetRequestSecret(appKey, true, requestKeyUri);
            var requestTime = TimeProcess.GetTimeStamp();
            var reSignStr = $"{appKey}{requestSecret}{requestTime}";
            var signStr = Md5Utils.GetStrMd5_32X(reSignStr);
            string requestUri = string.Format(billUri, appKey, requestTime, status, typhoonId, signStr);
            var response = await GetRequest<BaseIrsResponse<string>>(requestUri, ClientName);
            if (response == null)
            {
                throw new Exception("获取台风协同工作失败,返回结果为空!");
            }
            if (response.Code != SuccessCode)
            {
                if (response.Code == CityRequestKeyExpire && !reCount)
                {
                    await GetRequestSecret(appKey, false, requestKeyUri);
                    return await GetCollaboraiveWork(appKey, typhoonId, status, requestKeyUri, billUri, true);
                }
                throw new Exception($"获取台风协同工作失败，code: {response.Code}, msg: {response.Msg}");
            }
            return response.Datas;
        }

        public async Task<string> GetPondingRealtime(string appKey, string requestKeyUri, string billUri, bool reCount = false)
        {
            var requestSecret = await GetRequestSecret(appKey, true, requestKeyUri);
            var requestTime = TimeProcess.GetTimeStamp();
            var reSignStr = $"{appKey}{requestSecret}{requestTime}";
            var signStr = Md5Utils.GetStrMd5_32X(reSignStr);
            string requestUri = string.Format(billUri, appKey, requestTime, signStr);
            var response = await GetRequest<BaseIrsResponse<string>>(requestUri, ClientName);
            if (response == null)
            {
                throw new Exception("获取积水点数据失败,返回结果为空!");
            }
            if (response.Code != SuccessCode)
            {
                if (response.Code == CityRequestKeyExpire && !reCount)
                {
                    await GetRequestSecret(appKey, false, requestKeyUri);
                    return await GetPondingRealtime(appKey, requestKeyUri, billUri, true);
                }
                throw new Exception($"获取积水点数据失败，code: {response.Code}, msg: {response.Msg}");
            }
            return response.Datas;
        }

        public async Task<T> GetRequest<T>(string requestUri, string clientName)
        {
            var stopWatch = new Stopwatch();
            stopWatch.Start();
            var responseBody = await HttpRequester.GetAsync<T>(requestUri, clientName);
            stopWatch.Stop();
            //var quartzHttpLogAdapter = new QuartzHttpLogAdapter();
            //await quartzHttpLogAdapter.InsertAsync(new Adapter.Models.QuartzHttpLog()
            //{
            //    GuidRequest = Guid.NewGuid().ToString("N"),
            //    Uri = requestUri,
            //    RequestBody = string.Empty,
            //    ResponseBody = JsonSerializer.Serialize(responseBody),
            //    ElapsedMilliseconds = stopWatch.ElapsedMilliseconds,
            //    TimeCreate = DateTime.Now
            //});
            return responseBody;
        }
    }
}
